#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/wait.h>
#include <signal.h>
#include <sys/time.h>

void show_sigset(sigset_t set){
    for (int i = 1; i < 32; ++i) {
        // 判断信号是否存在
        if(sigismember(&set,i)){
            printf("1");
        }
        else{
            printf("0");
        }
    }
    putchar('\n');
}

/**
 * 信号集 ： sigset_t
 * 相关函数
 * @return
 */
//int main() {
//    int i = 0;
//    // 信号集 集合
//    sigset_t set;
//    // 清空信号集
//    sigemptyset(&set);
//    show_sigset(set);
//
//    // 将所有的信号加入集合中
//    sigfillset(&set);
//    show_sigset(set);
//
//    // 将信号2 3从信号集中去除
//    sigdelset(&set,SIGINT);
//    sigdelset(&set,SIGQUIT);
//    show_sigset(set);
//
//    // 将信号2 加入信号集
//    sigaddset(&set,SIGINT);
//    show_sigset(set);
//
//    return 0;
//}

void fun1(int signum){
    printf("fun1 catch signal %d \n",signum);
}

void fun2(int signum){
    printf("fun2 catch signal %d \n",signum);
}

/**
 * 屏蔽信号集
 *
 * @return
 */
//int main() {
//
//    int ret = -1;
//    sigset_t set;
//    sigset_t old;
//
//    // 信号注册 ctrl+c
//    signal(SIGINT,fun1);
//    // 信号注册 ctrl+'\' 这个信号不能出现 sleep
//    signal(SIGQUIT,fun2);
//
//    printf("按下任意键盘， 阻塞信号2\n");
//    getchar();
//    sigemptyset(&set);
//    sigemptyset(&old);
//    sigaddset(&set,SIGINT);
//    // 设置屏蔽编号为2的信号
//    ret = sigprocmask(SIG_BLOCK,&set,&old);
//    printf("设置成功\n");
//    printf("press any key to move sig 2 block\n");
//    getchar();
//    // 将信号屏蔽集设置为原来的
//    ret = sigprocmask(SIG_SETMASK,&old,NULL);
//    printf("press any key to exit\n");
//
//    return 0;
//}

/**
 * 读取当前进程的未决信号集
 * @return
 */
//int main() {
//
//    int ret = -1;
//    sigset_t set;
//    sigset_t old;
//
//    // 信号注册 ctrl+c
//    signal(SIGINT,fun1);
//    // 信号注册 ctrl+'\' 这个信号不能出现 sleep
//    signal(SIGQUIT,fun2);
//
//    printf("按下任意键盘， 阻塞信号2\n");
//    getchar();
//    sigemptyset(&set);
//    sigemptyset(&old);
//    sigaddset(&set,SIGINT);
//    sigaddset(&set,SIGQUIT);
//    // 设置屏蔽编号为2的信号
//    ret = sigprocmask(SIG_BLOCK,&set,&old);
//    printf("设置成功\n");
//
//    //获取未决信号集
//    printf("press key to get unselect signal\n");
//    getchar();
//    sigemptyset(&set);
//    sigpending(&set);
//    show_sigset(set);
//
//    printf("press any key to move sig 2 block\n");
//    getchar();
//    // 将信号屏蔽集设置为原来的
//    ret = sigprocmask(SIG_SETMASK,&old,NULL);
//    printf("press any key to exit\n");
//
//    return 0;
//}

/**
 * 新的信号处理函数
 * @param signo
 * @param info
 * @param context
 */
void fun3(int signo,siginfo_t * info,void *context){

    printf("get signal %d\n",signo);
}

/**
 * sigaction
 * 演示函数使用
 * @return
 */
//int main() {
//
//    int ret = -1;
//
//    /*struct sigaction {
//        void     (*sa_handler)(int);
//        void     (*sa_sigaction)(int, siginfo_t *, void *);
//        sigset_t   sa_mask;
//        int        sa_flags;
//        void     (*sa_restorer)(void); 放弃使用了
//    };*/
//#if 0
//    //这是原来的信号处理函数
//    // 定义对应的信号结构体
//    struct sigaction act;
//    // 使用旧的信号处理函数指针
//    act.sa_handler = fun1;
//    // 标志为默认，默认使用就旧的信号处理函数指针
//    act.sa_flags = 0;
//#else
//    //这是新的处理方式
//    struct sigaction act;
//    //使用新的信号处理函数指针
//    act.sa_sigaction = fun3;
//    act.sa_flags = SA_SIGINFO;
//#endif
//    //信号注册
//    ret = sigaction(SIGINT,&act,NULL);
//    printf("press any key to exit\n");
//    while(1)
//        getchar();
//    return 0;
//}

void fun4(int signo){
    printf("catch signal %d \n",signo);
    printf("have children exit\n");
    // 非阻塞方式 处理僵尸进程， -1 代表等待任意一个子进程， WNOHANG表示非阻塞
    while(waitpid(-1,NULL,WNOHANG));
}

/**
 * 避免僵尸进程的一种方式
 * @return
 */
int main() {

    int ret = -1;
    pid_t pid = -1;

    //这是原来的信号处理函数
    // 定义对应的信号结构体
    struct sigaction act;
    // 使用旧的信号处理函数指针
    act.sa_handler = fun4;
    // 标志为默认，默认使用就旧的信号处理函数指针
    act.sa_flags = 0;
    //信号注册
    ret = sigaction(SIGCHLD,&act,NULL);
    pid = fork();
    if(pid == 0){
        printf("child sleep\n");
        sleep(2);
        printf("chile sleep end exit\n");
        exit(0);
    }
    while(1){
        printf("parent working ....\n");
        sleep(1);
    }

    return 0;
}